/*
 *
 *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *
 *  Author : Raúl Román López <rroman@gsyc.es>
 *
 */

package com.BCNTours.AR.Vista;

import java.util.ArrayList;
import java.util.concurrent.Semaphore;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.graphics.Shader.TileMode;
import android.util.Log;
import android.view.View;

import com.BCNTours.R;
import com.BCNTours.AR.Utils.Coordinates;

/**
 * Draws the radar which display all the nearby points of interest located around the current position; used on ARactivity.
 */
public class DrawRadar extends View{

	//Attributes of the class
	private static float mRADIUS;									//Radius of the compass
	private static float mRADIUSANGLE;								//Angle of the vision range
	private static final float resourceRadius = 2;
	private static float maxRadiusResource;
	private static final float BORDER = 10;
	public static final float MAX_AZIMUTH_VISIBLE = 30;
	public static final double MAX_LOG_DISTANCE_SHOWN = 3.5;		//The maxim distance to draw point
	
	private Context mContext;
	private float azimuth;											//Angle between the magnetic north
	private ArrayList<Point> resources= null;						//List of the point
	
	private Bitmap compass_appearance = null;						//Image of the compass
	private Bitmap compass_shadow = null;							//Background of the compass
	
	@SuppressWarnings("unused")
	private Semaphore sem;											//Semaphore
	
	private boolean rotate_compass;									//The compass rotate or no
	
	
	public DrawRadar(Context context){
		super(context);
		
		//Get the images of the compass
		this.compass_appearance = BitmapFactory.decodeResource(getResources(),R.drawable.compass_simple);
		this.compass_shadow = BitmapFactory.decodeResource(getResources(),R.drawable.compass_simple_shadow);
		this.mContext = context;
		
		//Calculate the features of the compass 
		mRADIUS = ((float)compass_appearance.getWidth())/2;
		mRADIUSANGLE = mRADIUS - transformPixInDip(mContext, 4);
		maxRadiusResource = mRADIUSANGLE - transformPixInDip(mContext, resourceRadius);
		
		azimuth = 0;
		rotate_compass = true;
		sem = new Semaphore(1);
	}

	/**
	 * Set the angle between the magnetic north.
	 * @param azimuth Angle between the magnetic north direction and the Y axis, around the Z axis (0 to 359).*/
	public void setAzimuth(float azimuth){
		this.azimuth = azimuth;
		
	}
	
	/**
	 * Sets whether to rotate the compass or not.
	 * @param rotate 
	 */
	public void setRotateCompass(boolean rotate){
		this.rotate_compass = rotate;
	}
	
	@Override
	protected void onDraw(Canvas canvas){
		float compass_center_x = mRADIUS + BORDER;
        float compass_center_y = compass_center_x;
        
        // VISION RANGE
        Paint paintRange = new Paint();
		paintRange.setStyle(Paint.Style.FILL);
		paintRange.setShader(new RadialGradient(compass_center_x, compass_center_y, 
				mRADIUSANGLE, Color.WHITE, Color.YELLOW, TileMode.MIRROR));
		
        RectF oval = new RectF(compass_center_x - mRADIUSANGLE, compass_center_y - mRADIUSANGLE, 
        		compass_center_x + mRADIUSANGLE, compass_center_y + mRADIUSANGLE);
        
        float base = 0;
        if(!rotate_compass)
        	base = azimuth;
        canvas.drawArc(oval, base - 90 - MAX_AZIMUTH_VISIBLE,
        		MAX_AZIMUTH_VISIBLE*2, true, paintRange);
        
        // RADAR SHADOW
        canvas.drawBitmap(compass_shadow, compass_center_x - mRADIUS, 
        		compass_center_y - mRADIUS, null);
        
        // ROTATE THE COMPASS
        if(rotate_compass)
        	canvas.rotate(-azimuth, compass_center_x, compass_center_y);
        
        // RADAR BACKGROUND
        canvas.drawBitmap(compass_appearance, compass_center_x - mRADIUS, 
        		compass_center_y - mRADIUS, null);
		
		
		if(resources != null){
			Paint paint = new Paint();
		    paint.setStyle(Paint.Style.FILL);
		    paint.setARGB(255, 255, 255, 255);
		    
			int max = resources.size();
			for(int i = 0; i < max; i++){
					
				canvas.drawCircle(compass_center_x + (maxRadiusResource * resources.get(i).x)/100, 
						compass_center_y + (maxRadiusResource * resources.get(i).y)/100,
						resourceRadius, paint);
			}
		}
	}
	
    // Transformation of px in dip
    public static float transformPixInDip(Context mContext, float pix){
    	
    	return ((pix * mContext.getResources().getDisplayMetrics().density) + 0.5f);
    	
    }
    
    public void updateCoordRadar(Coordinates c, float azimuth, ArrayList<POIButton> poiButtons,int maxDist){
		//Declarations
    	float abs_azimuth;
    	float distance;
    	ArrayList<Point> points = new ArrayList<Point>();
    	
    	//Set the angle of the camera
    	setAzimuth(azimuth);
    	
    	//Calculate the position of the interesting point on the compass
		for (POIButton tmp : poiButtons) {
			
			abs_azimuth = c.getAngleToCam(tmp.getCoord(), azimuth);
			
			distance = c.getDistance_km(tmp.getCoord()) * 1000;
			Log.i("distance", Float.toString(distance));
		
			if(distance < (maxDist*1000)){
				points.add(new Point((int)(distanceLog(distance) * 100 * Math.sin(Math.toRadians(abs_azimuth))), 
						(int)(distanceLog(distance) * -100 * Math.cos(Math.toRadians(abs_azimuth)))));
			} else if(maxDist == 0){
				points.add(new Point((int)(distanceLog(distance) * 100 * Math.sin(Math.toRadians(abs_azimuth))), 
						(int)(distanceLog(distance) * -100 * Math.cos(Math.toRadians(abs_azimuth)))));
			}
		}
		//Save the actual list of the position of the interesting point on the compass
		resources = points;

    }

	private static double distanceLog(double dist){
		double log = 1;
		
		if(dist == 0)
			return 0;
		log = Math.max(1, Math.min(MAX_LOG_DISTANCE_SHOWN, Math.log10(dist)))/MAX_LOG_DISTANCE_SHOWN;
		
		return log;
	}
}